﻿//-----------------------------------------------------------------------
// <copyright file="ExceptionDataContract.cs" company="CodePlex">
//     Copyright (c) Doug Holland, CodePlex. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace CodePlex.Diagnostics.Silverlight.Contracts
{
    using System;

    using System.Collections;
    using System.Collections.Generic;

    using System.Diagnostics;

    using System.Reflection;

    using System.Runtime.Serialization;

    /// <summary>
    /// Represents errors that occur during application execution.
    /// </summary>
    [DataContract(Name = "ExceptionDataContract", Namespace = "http://schemas.datacontract.org/2004/07/CodePlex.Diagnostics.Contracts")]
    public sealed class ExceptionDataContract
    {
        #region public ExceptionDataContract(Exception ex)

        /// <summary>
        /// Initializes a new instance of the <see cref="T:ExceptionDataContract"/> class.
        /// </summary>
        /// <param name="ex">The <see cref="T:System.Exception"/> for which the <see cref="T:CodePlex.Diagnostics.Contracts.ExceptionDataContract"/> is required.</param>
        public ExceptionDataContract(Exception ex)
        {
            this.Data = ex.Data;

            this.HelpLink = null;

            Type type = ex.GetType();

            this.ExceptionType = type.FullName;

            //PropertyInfo[] properties = type.GetProperties(BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.Instance);

            //foreach (PropertyInfo property in properties)
            //{
            //    if (string.Equals(property.Name, "HResult"))
            //    {
            //        this.HResult = (int)property.GetValue(ex, null);
            //    }

            //    if (string.Equals(property.Name, "IsTransient"))
            //    {
            //        this.IsTransient = (bool)property.GetValue(ex, null);
            //    }
            //}

            this.InnerExceptions = new List<ExceptionDataContract>();

            if (ex.InnerException != null)
            {
                this.InnerExceptions.Add(new ExceptionDataContract(ex.InnerException));
            }

            this.Message = ex.Message;

            this.Source = null;

            this.StackTrace = ex.StackTrace;

            this.SerializedException = null;

            this.TargetSite = null;
        }

        #endregion

        #region public AppDomainDataContract AppDomain

        /// <summary>
        /// Gets or sets the application domain within which the current exception was thrown.
        /// </summary>
        /// <value>The application domain within which the current exception was thrown.</value>
        [DataMember]
        public AppDomainDataContract AppDomain
        {
            get;
            set;
        }

        #endregion

        #region public AssemblyDataContract Assembly

        /// <summary>
        /// Gets or sets the assembly containing the code within which the current exception was thrown.
        /// </summary>
        /// <value>The assembly containing the code within which the current exception was thrown.</value>
        [DataMember]
        public AssemblyDataContract Assembly
        {
            get;
            set;
        }

        #endregion

        #region public IDictionary Data

        /// <summary>
        /// Gets a collection of key/value pairs that provide additional user-defined information about the exception.
        /// </summary>
        /// <value>A collection of key/value pairs that provide additional user-defined information about the exception.</value>
        [DataMember]
        public IDictionary Data
        {
            get;
            private set;
        }

        #endregion

        #region public string ExceptionType

        /// <summary>
        /// Gets or sets the name of the exception type.
        /// </summary>
        /// <value>The name of the exception type.</value>
        [DataMember]
        public string ExceptionType
        {
            get;
            set;
        }

        #endregion

        #region public string HelpLink

        /// <summary>
        /// Gets a link to the help file associated with this exception.
        /// </summary>
        /// <value>A link to the help file associated with this exception.</value>
        [DataMember]
        public string HelpLink
        {
            get;
            private set;
        }

        #endregion

        #region public int? HResult

        /// <summary>
        /// Gets the HRESULT value, a coded numerical value that is assigned to a specific exception.
        /// </summary>
        /// <value>The HRESULT value, a coded numerical value that is assigned to a specific exception.</value>
        [DataMember]
        public int? HResult
        {
            get;
            private set;
        }

        #endregion

        #region public IList<ExceptionDataContract> InnerExceptions

        /// <summary>
        /// Gets the exception instance that caused the current exception.
        /// </summary>
        /// <value>The exception instance that caused the current exception.</value>
        [DataMember]
        public IList<ExceptionDataContract> InnerExceptions
        {
            get;
            private set;
        }

        #endregion

        #region public bool IsTransient

        /// <summary>
        /// Gets or sets a value indicating whether the exception is transient.
        /// </summary>
        /// <value>A value indicating whether the exception is transient.</value>
        public bool IsTransient
        {
            get;
            set;
        }

        #endregion

        #region public MachineDataContract Machine

        /// <summary>
        /// Gets or sets the machine upon which the current exception was thrown.
        /// </summary>
        /// <value>The machine upon which the current exception was thrown.</value>
        [DataMember]
        public MachineDataContract Machine
        {
            get;
            set;
        }

        #endregion

        #region public string Message

        /// <summary>
        /// Gets a message that describes the current exception.
        /// </summary>
        /// <value>The error message that explains the reason for the exception, or an empty string.</value>
        [DataMember]
        public string Message
        {
            get;
            private set;
        }

        #endregion

        #region public ProcessDataContract Process

        /// <summary>
        /// Gets or sets the process within which the current exception was thrown.
        /// </summary>
        /// <value>The process within which the current exception was thrown.</value>
        [DataMember]
        public ProcessDataContract Process
        {
            get;
            set;
        }

        #endregion

        #region public string Source

        /// <summary>
        /// Gets the name of the application or object that caused the error.
        /// </summary>
        /// <value>The name of the application or object that caused the error.</value>
        [DataMember]
        public string Source
        {
            get;
            private set;
        }

        #endregion

        #region public string StackTrace

        /// <summary>
        /// Gets a string representation of the frames in the call stack at the time the current exception was thrown.
        /// </summary>
        /// <value>A string that describes the contents of the call stack, with the most recent method call appearing first.</value>
        [DataMember]
        public string StackTrace
        {
            get;
            private set;
        }

        #endregion

        #region public string SerializedException

        /// <summary>
        /// Gets or sets a <see cref="T:System.String"/> containing the soap-encoded serialized <see cref="T:System.Exception"/> instance.
        /// </summary>
        /// <value>A <see cref="T:System.String"/> containing the soap-encoded serialized <see cref="T:System.Exception"/> instance.</value>
        [DataMember]
        public string SerializedException
        {
            get;
            set;
        }

        #endregion

        #region public bool Unhandled

        /// <summary>
        /// Gets or sets a value indicating whether the exception was unhandled.
        /// </summary>
        /// <value><c>true</c> if the exception was unhandled; otherwise, <c>false</c>.</value>
        [DataMember]
        public bool Unhandled
        {
            get;
            set;
        }

        #endregion

        #region public MethodBaseDataContract TargetSite

        /// <summary>
        /// Gets or sets the method that throws the current exception.
        /// </summary>
        /// <value>The method that throws the current exception.</value>
        [DataMember]
        public MethodBaseDataContract TargetSite
        {
            get;
            set;
        }

        #endregion

        #region public ThreadDataContract Thread

        /// <summary>
        /// Gets or sets the thread within which the current exception was thrown.
        /// </summary>
        /// <value>The thread within which the current exception was thrown.</value>
        [DataMember]
        public ThreadDataContract Thread
        {
            get;
            set;
        }

        #endregion

        #region public Exception DeserializedException

        /// <summary>
        /// Gets the deserialized <see cref="T:System.Security.Principal.IIdentity"/> instance.
        /// </summary>
        /// <value></value>
        public Exception DeserializedException
        {
            get
            {
                return null;
            }
        }

        #endregion
    }
}
